package services

import (
	"context"
	"crypto/rand"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"log"
	"time"

	"ai-collections/pkg/config"

	"github.com/redis/go-redis/v9"
)

// 令牌前缀
const (
	TokenKeyPrefix = "token:"
	TokenExpiry    = 3 * time.Minute // 3分钟过期
)

// RedisTokenService 提供基于Redis的令牌服务
type RedisTokenService struct {
	client *redis.Client
	ctx    context.Context
}

// 全局Redis令牌服务实例
var redisTokenService *RedisTokenService

// InitRedisTokenService 初始化Redis令牌服务
func InitRedisTokenService(cfg *config.RedisConfig) error {
	// 创建Redis客户端
	client := redis.NewClient(&redis.Options{
		Addr:     fmt.Sprintf("%s:%s", cfg.Host, cfg.Port),
		Password: cfg.Password,
		DB:       cfg.DB,
	})

	// 测试连接
	ctx := context.Background()
	_, err := client.Ping(ctx).Result()
	if err != nil {
		return fmt.Errorf("failed to connect to Redis: %v", err)
	}

	// 初始化服务
	redisTokenService = &RedisTokenService{
		client: client,
		ctx:    ctx,
	}

	log.Println("Redis token service initialized successfully")
	return nil
}

// GetRedisTokenService 返回Redis令牌服务实例
func GetRedisTokenService() (*RedisTokenService, error) {
	if redisTokenService == nil {
		return nil, fmt.Errorf("Redis token service not initialized")
	}
	return redisTokenService, nil
}

// CreateToken 创建一个新的一次性使用令牌
func (s *RedisTokenService) CreateToken(carID, channelType, userID string) (string, error) {
	// 生成随机令牌
	// token, err := generateRandomToken(32)
	// if err != nil {
	// 	return "", err
	// }

	// 创建令牌信息
	tokenInfo := TokenInfo{
		CarID:       carID,
		ChannelType: channelType,
		UserID:      userID,
		CreatedAt:   time.Now(),
		ExpiresAt:   time.Now().Add(TokenExpiry),
	}

	// 序列化令牌信息
	data, err := json.Marshal(tokenInfo)
	if err != nil {
		return "", err
	}

	// 存储到Redis，设置过期时间
	// key := TokenKeyPrefix + token
	err = s.client.Set(s.ctx, userID, data, TokenExpiry).Err()
	if err != nil {
		return "", err
	}

	log.Printf("Created one-time token for carID: %s, channel: %s, expires in: %v",
		carID, channelType, TokenExpiry)
	return userID, nil
}

// ValidateAndConsumeToken 验证并消费令牌（一次性使用）
func (s *RedisTokenService) ValidateAndConsumeToken(token string) (bool, TokenInfo, error) {
	key := token
	var tokenInfo TokenInfo

	// 获取令牌数据
	tokenData, err := s.client.Get(s.ctx, key).Bytes()
	if err != nil {
		if err == redis.Nil {
			return false, TokenInfo{}, fmt.Errorf("token not found or already used")
		}
		return false, TokenInfo{}, err
	}

	// 立即删除令牌（确保一次性使用）
	_, err = s.client.Del(s.ctx, key).Result()
	if err != nil {
		log.Printf("Warning: Failed to delete token after use: %v", err)
	}

	// 解析令牌信息
	if err := json.Unmarshal(tokenData, &tokenInfo); err != nil {
		return false, TokenInfo{}, err
	}

	// 检查是否过期
	if time.Now().After(tokenInfo.ExpiresAt) {
		return false, TokenInfo{}, fmt.Errorf("token expired")
	}

	log.Printf("Token validated and consumed for carID: %s", tokenInfo.CarID)
	return true, tokenInfo, nil
}

// Shutdown 关闭Redis连接
func (s *RedisTokenService) Shutdown() error {
	return s.client.Close()
}

// 生成随机令牌
func generateRandomToken(length int) (string, error) {
	bytes := make([]byte, length/2)
	if _, err := rand.Read(bytes); err != nil {
		return "", err
	}
	return hex.EncodeToString(bytes), nil
}
